package com.sainan114.pipelinestudy;

import com.sainan114.pipelinestudy.mapper.PipelineMapper;
import com.sainan114.pipelinestudy.mapper.StrategyMapper;
import com.sainan114.pipelinestudy.model.PipelineDO;
import com.sainan114.pipelinestudy.model.StrategyDO;
import com.sainan114.pipelinestudy.strategy.AbstractStrategy;
import com.sainan114.pipelinestudy.util.LogUtils;
import com.sainan114.pipelinestudy.util.PipelineParamsMap;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * @author lgb
 * @Date: 2021/7/10
 */
@Component
public class PipelineStart {
    @Resource
    PipelineMapper pipelineMapper;
    @Resource
    StrategyMapper strategyMapper;

    private final static DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    public static ThreadLocal<String> threadId = new ThreadLocal();


    List<AbstractStrategy> strategyList = new ArrayList<>();

    public void startPipeline(String pipelineName) {
        loadStrategy(pipelineName);
        handleStrategy();
    }

    private void loadStrategy(String pipelineName) {
        // 线程id先用uuid来代替，到时候，可以使用雪花算法或者redis递增id来设置
        threadId.set(UUID.randomUUID().toString());

        // 1. 获取Pipeline信息
        PipelineDO pipelineDO = pipelineMapper.queryByPipelineName(pipelineName);

        if (pipelineDO == null) {
            LogUtils.errorLog("pipelineDo is null");
            throw new RuntimeException("pipelineDo is null");
        }

        String strategyRule = pipelineDO.getStrategyRule();
        if (StringUtils.isBlank(strategyRule)) {
            LogUtils.errorLog("strategyRule is null");
            throw new RuntimeException("strategyRule is null");
        }
        // 2. 获取pipeline对应的strategy信息
        List<String> strategiesNameList = divisionStrategyName(strategyRule);
        // 3. 将strategy转换成bean
        getStrategiesByName(strategiesNameList);
    }

    private void handleStrategy() {
        LogUtils.infoLog("strategy start. strategiesList: " + strategyList + "time :" +
                timeFormatter.format(LocalDateTime.now()));
        for (AbstractStrategy strategy : strategyList) {
            setStrategiesQLRule(strategy);
            strategy.startStrategy();
        }
        LogUtils.infoLog("strategy end. time :" +
                timeFormatter.format(LocalDateTime.now()));
        threadId.remove();
    }


    private List<String> divisionStrategyName(String strategyRule) {
        String[] strategies = strategyRule.split(",");
        ArrayList<String> strategyRuleList = new ArrayList<>();
        for (String strategy : strategies) {
            if (StringUtils.isBlank(strategy)) {
                LogUtils.infoLog("one strategy is empty strategyRule:" +strategyRule);
                continue;
            }
            strategyRuleList.add(strategy);
        }
        return strategyRuleList;
    }

    private void getStrategiesByName(List<String> strategyRuleList) {
        if (CollectionUtils.isEmpty(strategyRuleList)) {
            return ;
        }

        for (String strategyName : strategyRuleList) {
            AbstractStrategy strategy = StrategyFactory.getBean(strategyName);
            if (strategy == null) {
                LogUtils.infoLog("strategy :" + strategyName + "get bean failure");
                continue;
            }
            strategyList.add(strategy);
        }
    }
    /**
     * 既然是每个Strategy都有自己的ql表达式，肯定是需要从数据库找的。
     * 选择了模板方法的话，就先提前找出来，这样子类就不需要再实现这个方法了
     * 至于传参问题，可以使用map来进存储。
     */
    private void setStrategiesQLRule(AbstractStrategy strategy) {

        String beanName = strategy.getClass().getSimpleName();
        StrategyDO strategyDO = strategyMapper.queryStrategyByName(beanName);
        if (strategyDO == null) {
            LogUtils.infoLog(beanName + "not information in mysql");
            return;
        }
        String rule = strategyDO.getRule();
        PipelineParamsMap.setStrategyRule(rule);
    }
}
